import * as d3 from 'd3'
export class WindGauge {
  divId = ''
  data = 0
  dataDomain = [0, 50, 100]
  bdata = [0, 0.2, 1.5, 3.3, 5.4, 7.9, 10.7, 13.8, 17.1, 20.7, 24.4, 28.4, 32.6, 36.9, 41.4, 46.1, 50.9, 56.0]
  arcMin = -Math.PI * 0.8
  arcMax = Math.PI * 0.8
  range = this.arcMax - this.arcMin
  innerRadius = 60
  outerRadius = 80
  labelPad = 10
  arc = d3.arc()
  arcScale = d3.scaleLinear()
  positionX = 0
  positionY = 0
  selection = ''
  chart = {}

  constructor(divId) {
    this.divId = divId
  }

  draw() {
    this.initChart()
    this.initLayout()
    this.initGauge()
    this.drawDataArc()
  }

  update() {
    this.drawDataArc()
  }

  initChart() {
    this.chart.padding = {
      left: 20,
      right: 50,
      top: 20,
      bottom: 20
    }
    this.chart.divHeight = document.getElementById(this.divId).offsetHeight -
      this.chart.padding.top -
      this.chart.padding.bottom
    this.chart.divWidth = document.getElementById(this.divId).offsetWidth -
      this.chart.padding.left -
      this.chart.padding.right

    this.chart.svg = d3.select('#' + this.divId).append('svg')
      .attr('width', this.chart.divWidth + this.chart.padding.left + this.chart.padding.right)
      .attr('height', this.chart.divHeight + this.chart.padding.top + this.chart.padding.bottom)
      .attr('class', 'svg_chart')
  }

  initLayout(selection) {
    if (selection === '' || selection === undefined) {
      this.initChart()
      this.selection = this.chart.svg
    } else this.selection = selection

    this.arcScale.domain(this.dataDomain).range([this.arcMin, 0, this.arcMax])

    this.arc.innerRadius(this.innerRadius)
      .outerRadius(this.outerRadius)
      .startAngle(this.arcMin)
  }

  initGauge() {
    let gauge = this.selection.append('g')
      .attr('class', 'gauge')
      .attr('transform', 'translate(' + this.positionX + ',' + this.positionY + ')')

    gauge.append('path')
      .attr('d', this.arc({
        startAngle: this.arcMin,
        endAngle: this.arcMax
      }))
      .style('fill', '#ddd')

    this.drawDataArc()

    // 标识刻度
    // this.setGraduated(this.bdata)
    this.selection.select('.gauge').append('g')
      .attr('class', 'ticks')

    // 大尺度刻度的设置
    let boption = {
      data: this.bdata,
      className: 'speed',
      pointLength: 0.8,
      strokeWidth: 1.5,
      color: 'orange'
    }

    // 小尺度刻度的设置
    let soption = {
      data: this.bdata,
      className: 'level',
      pointLength: 0.9,
      strokeWidth: 1.5,
      color: 'red'
    }

    // 刻度绘制
    this.drawTicks(boption, 'speed')
    this.drawTicks(soption, 'level')

    // 指针及显示的数字的绘制
    this.drawShowPoint()
  }

  drawShowPoint() {
    let gauge = this.selection.select('.gauge')
    gauge.append('g')
      .append('polygon')
      .attr('class', 'point')
      .attr('points', `-2,-10,2,-10,4,0,1,${this.innerRadius * 0.8},-1,${this.innerRadius * 0.8},-4,0`)
      .attr('fill', '#ddd')
      .attr('transform', 'rotate(90)')

    gauge.append('text')
      .attr('class', 'showData')
      .attr('x', -10)
      .attr('y', 20)
      .style('font-size', 10)
      .text(0)
  }

  drawTicks(option, flag) {
    let gauge = this.selection.select('.gauge')

    gauge.select('.ticks')
      .selectAll('.' + option.className)
      .data(option.data)
      .enter()
      .append('line')
      .attr('class', option.className)
      .attr('x1', (_, i) => {
        if (flag === 'speed') {
          return this.innerRadius * Math.sin(this.arcScale(100 / option.data.length * i))
        } else {
          return (this.innerRadius + (this.outerRadius - this.innerRadius) / 2) *
           Math.sin(this.arcScale(100 / option.data.length * (i + 0.5)))
        }
      })
      .attr('y1', (_, i) => {
        if (flag === 'speed') {
          return this.innerRadius * Math.cos(this.arcScale(100 / option.data.length * i)) * -1
        } else {
          return (this.innerRadius + (this.outerRadius - this.innerRadius) / 2) *
           Math.cos(this.arcScale(100 / option.data.length * (i + 0.5))) * -1
        }
      })
      .attr('x2', (_, i) => {
        if (flag === 'speed') {
          return this.outerRadius * 1.1 * Math.sin(this.arcScale(100 / option.data.length * i))
        } else {
          return this.innerRadius * 0.9 * Math.sin(this.arcScale(100 / option.data.length * (i + 0.5)))
        }
      })
      .attr('y2', (_, i) => {
        if (flag === 'speed') {
          return this.outerRadius * Math.cos(this.arcScale(100 / option.data.length * i)) * -1.1
        } else {
          return this.innerRadius * Math.cos(this.arcScale(100 / option.data.length * (i + 0.5))) * -0.9
        }
      })
      .style('fill', option.color)
      .style('stroke', option.color)
      .style('stroke-width', option.strokeWidth)

    if (flag === 'speed') {
      gauge.append('line')
        .attr('class', option.className)
        .attr('x1', this.innerRadius * Math.sin(this.arcScale(100)))
        .attr('y1', this.innerRadius * Math.cos(this.arcScale(100)) * -1)
        .attr('x2', this.outerRadius * 1.1 * Math.sin(this.arcScale(100)))
        .attr('y2', this.outerRadius * Math.cos(this.arcScale(100)) * -1.1)
        .style('fill', option.color)
        .style('stroke', option.color)
        .style('stroke-width', option.strokeWidth)
    }
  }

  setGraduated(data) {
    let ticks = this.selection.select('.gauge').append('g')
      .attr('class', 'ticks')

    let ticksLabels = ticks.selectAll('.label')
      .data(data)
      .enter()
      .append('g')
      .attr('class', 'ticksLabels')

    ticksLabels.append('text')
      .attr('class', 'speed-label')
      .attr('x', (_, i) => this.outerRadius * Math.sin(this.arcScale(100 / data.length * i)) * 1.15)
      .attr('y', (_, i) => this.outerRadius * Math.cos(this.arcScale(100 / data.length * i)) * -1.15)
      .style('font-size', 12)
      .text(String)
      .filter(function(_, i) {
        return i < data.length / 2
      })
      .attr('dx', '-1em')

    ticksLabels.append('text')
      .attr('class', 'level-label')
      .attr('x', (_, i) => this.innerRadius * 1.05 * Math.sin(this.arcScale(100 / data.length * (i + 0.5))) * 0.8)
      .attr('y', (_, i) => this.innerRadius * Math.cos(this.arcScale(100 / data.length * (i + 0.5))) * -0.8)
      .style('font-size', 10)
      .text((_, i) => i)
      .filter(function(_, i) {
        return i > data.length / 2
      })
      .attr('dy', '0.5em')
      .attr('dx', '-0.7em')
  }

  drawDataArc() {
    let level = 0
    for (let i = 0; i < this.bdata.length; ++i) {
      if (this.data > this.bdata[i] && this.data < this.bdata[i + 1]) {
        level = i + (this.data - this.bdata[i]) / (this.bdata[i + 1] - this.bdata[i])
      }
    }
    this.selection.select('.gauge')
      .selectAll('.dataArc')
      .data([{
        startAngle: this.arcMin,
        endAngle: this.arcMin
      }])
      .enter()
      .append('path')
      .attr('class', 'dataArc')
      .attr('d', this.arc)
      .style('fill', '#1a9641')
      .each(function(d) {
        this._current = d
      })

    let gauge = this.selection.selectAll('.dataArc')

    gauge.data([{
      startAngle: this.arcMin,
      endAngle: this.arcScale(100 / this.bdata.length * level)
    }])
      .transition()
      .duration(1000)
      .attrTween('d', arcTween)

    this.selection.select('.showData').text(this.data)

    this.selection.select('.point')
      .transition()
      .duration(1000)
      .attr('transform', () => {
        let angle = this.arcScale(this.data) - this.arcMin
        return 'rotate(' + (90 + angle / this.range * 180) + ')'
      })
    let arc = this.arc

    function arcTween(a) {
      var i = d3.interpolate(this._current, a)
      this._current = i(0)
      return function(t) {
        return arc(i(t))
      }
    }
  }
}
